import { defineStore } from 'pinia'
import { useUIStore } from '@/store/ui'
import { useTreeStore } from '@/store/tree'
import { useConfigStore } from "@/store/config"
import { useTrack } from '@/hooks'
import StateData from './utils/data'
import { useInit, useStart, useLog, useReconnect } from './utils/hooks'
import useWxShare from '@/hooks/useWxShare'
import { start as startApi, reset, goon, next, pause, explainToQa, question, randomQuestion as rq, getQuestions } from '@/apis/ttsa'
import { useBranch, closeBranch, closeMenuTree, useTost } from '@/utils/comps'
import { MODE, PROCESS_TYPES, UIEVENTTYPES, NO_LOGO_IDS } from '@/constants/ttsa'
import { isWechat, isIos } from '@/utils/client'
import { useNetworkStore } from '@/store/network'

export const useTtsaStore = defineStore({
  id: 'ttsaStore',
  state: () => StateData,
  getters: {
    hasController: (state) => ![
      PROCESS_TYPES.beforeInit,
      PROCESS_TYPES.init,
      PROCESS_TYPES.loading,
      PROCESS_TYPES.beforeStart,
      PROCESS_TYPES.opened,
      PROCESS_TYPES.error,
      // PROCESS_TYPES.end // end时也显示导航信息
    ].includes(state.process)
  },
  actions: {
    // 初始化操作
    async init() {
      this.process = PROCESS_TYPES.beforeInit
      try {
        this.ttsa = await useInit()
      } catch {
        this.process = PROCESS_TYPES.error
      }
      this.process = PROCESS_TYPES.init
      return useStart(this.ttsa).then(() => {
        this.process = PROCESS_TYPES.opened
        // 切换网络 - 后端获取清晰度匹配音质
        const network = useNetworkStore()
        const bitrateName = localStorage.getItem('x-bitrate-name')
        network.adj(bitrateName || 'medium', true);
        const video: HTMLMediaElement = document.querySelector('#ttsa video')
        if (video) {
          // 被外部暂停video后执行播放及内部暂停
          video.onpause = () => {
            if (!this.asrPause) {
              video.play()
              this.pause()
            }
          }
        }
      }).catch(() => {
        useLog('ttsa-init error')
        this.error('数字人连接失败，请重试')
      })
    },
    // 重新链接操作
    async reconnect() {
      if (this.reconnecting || !this.hasController) return
      console.log('重新链接');
      closeBranch()
      closeMenuTree()
      this.widget_close({ axis_id: 'all' })
      this.reconnecting = true
      this.reconnecStatus = 'start'
      await pause({ pattern: this.mode })
      return useReconnect(this.ttsa).then(async () => {
        console.log('重新链接成功');
        await pause({ pattern: this.mode })
        this.reconnecting = false
        this.reconnecStatus = 'success'
      }).catch(() => {
        console.log('重新链接失败');
        this.reconnecting = false
        this.reconnecStatus = 'error'
      })
    },
    showController() {
      if (!this.hasController || this.mode === MODE.QA) return;
      this.controller = !this.controller;
    },
    // 会话开始
    start() {
      const video: HTMLMediaElement = document.querySelector('#ttsa video')
      if (video) {
        video.muted = false
        video.play()
      }
      this.apiLoading = true
      startApi({ vhop_user_id: this.ttsa.token?.user_id, pattern: this.mode, ...this.startParam })
        .then((res: API_RESULT) => {
          this.apiLoading = false
          getQuestions().then((data) => this.questions = data?.all_questions || [])
          const { process, end_content_id, end_node_id, enter_with_link, nobody_id, somebody_id, pattern, node_data } = res
          this.$patch({ nobodyId: nobody_id, somebodyId: somebody_id, mode: pattern || this.mode, process, endNode: { content_id: end_content_id, node_id: end_node_id } })
          if (enter_with_link) {
            this.setRes(res)
            return
          } else if (node_data) {
            useTreeStore().setCurrent(node_data)
          }
          if (res.has_history) {
            useBranch({
              close: false,
              title: '还想继续上次的话题吗？',
              skip: false,
              data: [
                { node_id: 'new', node_name: '从头听讲解' },
                { node_id: 'goon', node_name: '从上次中断的位置继续讲解' },
              ],
              handEvent: ({ node_id }) => this[node_id]()
            })
          }
        })
        .catch(() => {
          this.apiLoading = false
          useLog('api-start error')
          this.error('您没有抢到房间，再试试？')
        })
    },
    // 新节点播放
    new() {
      if (this.voiceLoading) this.unexpected = true
      this.apiLoading = true
      reset()
        .then((res: API_RESULT) => {
          this.apiLoading = false
          this.setRes(res)
        })
        .catch(() => {
          this.apiLoading = false
          useLog('api-new error')
          this.error('数字人连接出错，请重新连接')
        })
    },
    // 上次未完成节点信息
    goon(turnBack?) {
      const video: HTMLMediaElement = document.querySelector('#ttsa video')
      if (video) video.play()
      if (this.voiceLoading) this.unexpected = true
      this.apiLoading = true
      useLog('goon-start success')
      this.resetMuted()
      return goon({ pattern: this.mode, goon_to_next: turnBack === 'next' ? true : false })
        .then((res) => {
          this.apiLoading = false
          useLog('goon-end success')
          this.setRes(res)
          return Promise.resolve()
        })
        .catch(() => {
          this.apiLoading = false
          useLog('api-goon error')
          this.error('数字人连接出错，请重新连接')
        })
    },
    // 下一个节点
    next(data?) {
      const video: HTMLMediaElement = document.querySelector('#ttsa video')
      if (video) video.play()
      useLog('next start')
      if (this.voiceLoading) this.unexpected = true
      this.apiLoading = true
      next(data)
        .then((res: API_RESULT) => {
          this.apiLoading = false
          useLog('next-end success')
          this.setRes(res)
        })
        .catch(() => {
          this.apiLoading = false
          useLog('next-end error')
          this.error('数字人连接出错，请重新连接')
        })
    },
    // 节点变化返回值操作
    async setRes(res: API_RESULT) {
      const { process, process_id, is_branch_selection, branch_selection_data, pattern, node_data, jump_return_content_id, jump_return_node_id, peek_return_content_id, peek_return_node_id, peek_return_node_name, is_return_peek = false } = res
      this.$patch({ mode: pattern || this.mode, process, process_id })

      // 结束节点获取分享配置
      if (isWechat() && [PROCESS_TYPES.end].includes(process)) {
        const config = useConfigStore()
        await config.getShareConfig(node_data.id)
        useWxShare().handShare()
      }
      if (process === PROCESS_TYPES.idle_response) {
        this.paused = true
        return
      }
      if ([PROCESS_TYPES.end].includes(process)) return
      this.$patch({ is_return_peek })
      // peek跳出节点的信息
      if (jump_return_node_id && jump_return_content_id) {
        this.peekBackInfo = {
          jump_type: 'jump_to',
          content_id: jump_return_content_id,
          node_id: jump_return_node_id
        }
      } else {
        this.peekBackInfo = {}
      }
      // peek跳出历史节点的信息
      this.peekHistory.node_id = peek_return_node_id || ''
      this.peekHistory.content_id = peek_return_content_id || ''
      this.peekHistory.node_name = peek_return_node_name || ''
      // 不显示logo的节点id
      if (NO_LOGO_IDS.includes(node_data.id)) {
        this.hasLogo = false
      } else {
        this.hasLogo = true
      }

      if (node_data.content) {
        await useTreeStore().setCurrent(node_data)
        useTrack().setTrack({
          name: 'content_hit',
          process_id: process_id,
          content_id: node_data.content,
          node_id: node_data?.id
        })
      }
      closeBranch()
      if (is_branch_selection) {
        useBranch({
          close: true,
          data: branch_selection_data,
          handEvent: ({ content_id, node_id, skip }) => {
            if (skip) this.next({ jump_type: 'no_transition' })
            else this.next({ node_id, content_id, jump_type: 'no_transition' })
          },
        })
      }
    },
    // 暂停
    async pause() {
      this.apiLoading = true
      this.paused = true
      return pause({ pattern: this.mode })
        .then((res: API_RESULT) => {
          useLog('pause-end success')
          closeBranch()
          this.apiLoading = false
          this.process = res.process
          return Promise.resolve(res)
        }).catch(() => {
          this.apiLoading = false
          useLog('pause-end error')
          this.error('数字人连接出错，请重新连接')
        })
    },
    // UIEVENT 回调事件
    uicallback(uiCallback) {
      const { type, data } = uiCallback.callback_info
      useLog(`UIEVENT: ${type}`, data)
      switch (type) {
        case UIEVENTTYPES.voice_start:
          this.voice_start()
          break
        case UIEVENTTYPES.voice_end:
          this.voice_end()
          break
        case UIEVENTTYPES.subtitle_on:
          this.subtitles = data.text
          break
        case UIEVENTTYPES.subtitle_off:
          this.subtitles = ''
          break
        case UIEVENTTYPES.widget_close:
          this.widget_close(data)
          break
        default:
          if (type.includes('widget_')) this.widget_open(type, data)
          break
      }
    },
    // 语料开始
    voice_start() {
      this.paused = false
      this.voiceLoading = true
      this.widget_close({ axis_id: 'all' })
    },
    // 语料结束
    voice_end() {
      this.voiceLoading = false
      this.voiceActiveId = ''
      this.subtitles = ''
      if (this.unexpected) {
        this.unexpected = false
        this.break = false
        return
      }
      useTreeStore().clearPerGo()
      if (this.break) {
        this.break = false
        return
      }
      if (this.paused) return
      if (this.process !== PROCESS_TYPES.interrupt) closeBranch()
      if (this.process === PROCESS_TYPES.answer) {
        if (this.turnBack) {
          const turnBack = this.turnBack
          this.turnBack = ''
          this.qaToExplain(turnBack)
        } else {
          rq()
          this.process = PROCESS_TYPES.interrupt
        }
        return
      }
      switch (this.process) {
        case PROCESS_TYPES.start:
          this.new()
          break
        case PROCESS_TYPES.end:
          this.paused = true
          break
        case PROCESS_TYPES.new:
        case PROCESS_TYPES.goon:
        case PROCESS_TYPES.next:
          this.next()
          break
        case PROCESS_TYPES.qa_to_explain:
          this.goon()
          break
        default:
          break
      }
    },
    // 组件出现
    widget_open(type, data) {
      const uiStore = useUIStore()
      uiStore.addUI({ type, ...data })
      if (data.pause === 'true') this.pause()
    },
    // 组件消失
    widget_close({ axis_id }) {
      const uiStore = useUIStore()
      axis_id === 'all' ? uiStore.clear() : uiStore.delUI(axis_id)
    },
    // 问答
    async chat(questionTitle: string, other?: { asr_sessionid?: string, from?: string, chat_direct?: boolean }) {
      if (this.voiceLoading) this.unexpected = true
      this.resetMuted()
      const { setTrack } = useTrack()
      setTrack({
        name: 'ask',
        query_text: questionTitle,
        ...(other?.asr_sessionid && {
          asr_sessionid: other.asr_sessionid
        })
      })
      this.apiLoading = true
      return question(questionTitle, true, other && other.chat_direct).then((res) => {
        this.apiLoading = false
        this.process = PROCESS_TYPES.answer
        this.mode = res.pattern || this.mode
        const { nlp_query_text, is_list, hit } = res
        if (is_list) {
          useBranch({
            title: '您是否想问这些：',
            closeText: '关闭',
            type: 'ask',
            skip: false,
            data: nlp_query_text.map((n, i) => ({ node_id: `qa_i_${i}`, node_name: n })).concat({ node_id: 'qa_i_orther', node_name: '都不是我想问的' }),
            handEvent: ({ node_name }) => this.chat(node_name, node_name !== '都不是我想问的' && { chat_direct: true }),
          })
        }
        // 上报接口命中
        if (hit || is_list) {
          setTrack({
            name: 'ask_hit',
            type: other?.from ? 'click_link' : (hit ? 'node' : 'question_list'),
            query_text: questionTitle,
            nlp_query_text: nlp_query_text
          })
        }
        return Promise.resolve()
      }).catch((res) => {
        this.apiLoading = false
        return Promise.reject(res)
      })
    },
    // 讲解跳问答
    async explainToQa(content?: string) {
      this.mode = MODE.QA
      if (this.voiceLoading) this.unexpected = true
      closeBranch()
      this.widget_close({ axis_id: 'all' })
      if (content) {
        if (!this.paused) await this.pause()
        await this.chat(content, { from: 'click_link' })
      } else {
        const res = await explainToQa()
        this.$patch({ paused: true, process: PROCESS_TYPES.explain_to_qa, mode: res.pattern || this.mode })
      }
      useWxShare().handShare()
    },
    // 问答跳讲解
    async qaToExplain(turnBack?) {
      this.$patch({ process: PROCESS_TYPES.qa_to_explain })
      await this.pause()
      if (this.peekHistory.content_id) {
        this.next(this.peekHistory)
      } else {
        this.goon(turnBack)
      }
      useWxShare().handShare()
    },
    // ios下video被其他进程导致静音需重新设置muted
    resetMuted() {
      if (isIos()) {
        const video: HTMLMediaElement = document.querySelector('#ttsa video')
        if (video) {
          video.muted = true
          video.muted = false
        }
      }
    },
    error(msg = '', isClose = false) {
      this.process = PROCESS_TYPES.error
      this.hasDataStream = false
      if (!isClose) this.ttsa.closeRoom()
      useTost(msg)
      closeBranch()
      closeMenuTree()
    },
  },
})
